package com.docjohnson.pamphlet.views;

import java.util.Random;
import java.util.Set;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.docjohnson.pamphlet.utils.Constants;
import com.docjohnson.pamphlet.utils.LruCache;

public class ScreenSaverView extends View {
	private static final String TAG = ScreenSaverView.class.getSimpleName();

	private String[] imageList;

	Thread thread = new Thread();

	private RectF bitmapRect = new RectF();
	private RectF screenRect = new RectF();

	private Matrix matrix = new Matrix();

	private Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
	private Paint erasePaint = new Paint();
	private Paint addPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
	private Paint normalPaint = new Paint(Paint.FILTER_BITMAP_FLAG);

	
	private int currentBg = 0;
	private int animatingBg1;
	private int animatingBg2;
	
	private LruCache<Integer, Bitmap> cache = new LruCache<Integer, Bitmap>(12 * 1024 * 1024) {
		
		@Override
		public void entryRemoved(Integer key, Bitmap value) {
			value.recycle();
			Log.d(TAG, "entryRemoved, key : " + key);
		}
		
		@Override
		protected int sizeOf(Integer key, Bitmap value) {
			return value.getByteCount();
		}
		
		@Override
		public Bitmap create(Integer key) {
			Bitmap big = BitmapFactory.decodeFile(imageList[key]);
			bitmapRect.set(0, 0, big.getWidth(), big.getHeight());

			matrix.setRectToRect(bitmapRect, screenRect, ScaleToFit.CENTER);
			matrix.mapRect(bitmapRect);

			Bitmap bmp = Bitmap.createScaledBitmap(big, (int) bitmapRect.width(),
					(int) bitmapRect.height(), true);
			
			if (bmp != big)
				big.recycle();
			
			Log.d(TAG, "created bitmap " + key);
			
			return bmp;
		}
	};
	
	public ScreenSaverView(Context context, AttributeSet attrs) {
		super(context, attrs);

		addPaint.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP));
		erasePaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		
		Log.d(TAG, "onLayout");
		
		screenRect.set(left, top, right, bottom);
		
		int t = currentBg + 1;

		if (t == imageList.length - 1) {
			t = 0;
		}

		animateBackgrounds(currentBg, t);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		((Activity) getContext()).finish();
		return super.onTouchEvent(event);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		drawBackground(canvas, normalPaint);
	}

	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		
		cache.clear();
	}

	public void setImageList(Set<String> imageListSet) {
		if (imageListSet != null)
			imageList = imageListSet.toArray(new String[0]);
		else {
			((Activity) getContext()).finish();
		}
	}

	private Random random = new Random(System.currentTimeMillis());

	private boolean fadeAnimating = false;
	private int alpha1, alpha2;

	private void drawBackground(Canvas canvas, Paint paint) {
		if (fadeAnimating) {
			bitmapRect.set(0, 0, cache.get(animatingBg1).getWidth(), cache.get(animatingBg1).getHeight());
			matrix.setRectToRect(bitmapRect, screenRect, ScaleToFit.CENTER);
			paint.setAlpha(alpha1);
			canvas.drawBitmap(cache.get(animatingBg1), matrix, paint);
			
			bitmapRect.set(0, 0, cache.get(animatingBg2).getWidth(), cache.get(animatingBg2).getHeight());
			matrix.setRectToRect(bitmapRect, screenRect, ScaleToFit.CENTER);
			paint.setAlpha(alpha2);
			canvas.drawBitmap(cache.get(animatingBg2), matrix, paint);
		} else {
			bitmapRect.set(0, 0, cache.get(currentBg).getWidth(), cache.get(currentBg).getHeight());
			matrix.setRectToRect(bitmapRect, screenRect, ScaleToFit.CENTER);
			paint.setAlpha(255);
			canvas.drawBitmap(cache.get(currentBg), matrix, paint);
		}
	}

	private void animateBackgrounds(final int from, final int to) {
		ValueAnimator fade = ValueAnimator.ofInt(255, 0);
		fade.setStartDelay(Constants.SCREEN_SAVER_BACKGROUND_CHAGE_DELAY);
		fade.setDuration(5000);
		fade.addUpdateListener(new AnimatorUpdateListener() {

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				alpha1 = (Integer) animation.getAnimatedValue();
				alpha2 = 255 - alpha1;
			}
		});

		fade.addListener(new AnimatorListener() {

			@Override
			public void onAnimationStart(Animator arg0) {
				fadeAnimating = true;
				
				animatingBg1 = currentBg;
				animatingBg2 = to;
			}

			@Override
			public void onAnimationRepeat(Animator arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onAnimationEnd(Animator arg0) {
				fadeAnimating = false;
				currentBg = to;
				int t = to + 1;
				if (t == imageList.length - 1) {
					t = 0;
				}
				currentBg = animatingBg2;
				animateBackgrounds(currentBg, t);
			}

			@Override
			public void onAnimationCancel(Animator arg0) {
				// TODO Auto-generated method stub

			}
		});

		fade.start();
	}

	public void recycleBitmaps() {
		cache.clear();
	}
}
